<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./leader-line.min.js"></script>

    <!--    <script src="./anim-event.esm.js"></script>-->
    <script>
        /* ================================================
        DON'T MANUALLY EDIT THIS FILE
================================================ */

        /*
         * AnimEvent
         * https://github.com/anseki/anim-event
         *
         * Copyright (c) 2018 anseki
         * Licensed under the MIT license.
         */

        var MSPF = 1000 / 60,
            // ms/frame (FPS: 60)
            KEEP_LOOP = 500,


            /**
             * @typedef {Object} task
             * @property {Event} event
             * @property {function} listener
             */

            /** @type {task[]} */
            tasks = [];

        var requestAnim = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) {
                return setTimeout(callback, MSPF);
            },
            cancelAnim = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame || window.msCancelAnimationFrame || function (requestID) {
                return clearTimeout(requestID);
            };

        var lastFrameTime = Date.now(),
            requestID = void 0;

        function step() {
            var called = void 0,
                next = void 0;

            if (requestID) {
                cancelAnim.call(window, requestID);
                requestID = null;
            }

            tasks.forEach(function (task) {
                var event = void 0;
                if (event = task.event) {
                    task.event = null; // Clear it before `task.listener()` because that might fire another event.
                    task.listener(event);
                    called = true;
                }
            });

            if (called) {
                lastFrameTime = Date.now();
                next = true;
            } else if (Date.now() - lastFrameTime < KEEP_LOOP) {
                // Go on for a while
                next = true;
            }
            if (next) {
                requestID = requestAnim.call(window, step);
            }
        }

        function indexOfTasks(listener) {
            var index = -1;
            tasks.some(function (task, i) {
                if (task.listener === listener) {
                    index = i;
                    return true;
                }
                return false;
            });
            return index;
        }

        var AnimEvent = {
            /**
             * @param {function} listener - An event listener.
             * @returns {(function|null)} A wrapped event listener.
             */
            add: function add(listener) {
                var task = void 0;
                if (indexOfTasks(listener) === -1) {
                    tasks.push(task = { listener: listener });
                    return function (event) {
                        task.event = event;
                        if (!requestID) {
                            step();
                        }
                    };
                }
                return null;
            },
            remove: function remove(listener) {
                var iRemove = void 0;
                if ((iRemove = indexOfTasks(listener)) > -1) {
                    tasks.splice(iRemove, 1);
                    if (!tasks.length && requestID) {
                        cancelAnim.call(window, requestID);
                        requestID = null;
                    }
                }
            }
        };
    </script>
    <style>
        *{
            padding: 0;
            margin: 0;
        }
        .target {
            display: inline-block;
            background-color: #9ee7ea;
            width: 60px;
            height: 40px;
            /*padding: 12px;*/
        }
        .target:hover{
            background-color: darkorange;
        }
        .box{
            width: 200px;
            height: 200px;
        }
        #start {}

        /*#end {*/
        /*    float: right;*/
        /*    margin-top: 200px;*/
        /*}*/

    </style>
</head>
<body>
<div class="box">
    <div id="start" class="target" >start</div>
    <div id="end" class="target">end</div>
    <div id="start2" class="target" >start2</div>
    <div id="end2" class="target">end2</div>
</div>

<script>
    // new LeaderLine(
    //     document.getElementById('start'),
    //     document.getElementById('end')
    // );

    var startEle = document.getElementById('start');
    var endEle = document.getElementById('end');

    var startEle2 = document.getElementById('start2');
    var endEle2 = document.getElementById('end2');


    function getTop(e) {
        var offset = e.offsetTop;
        if (e.offsetParent != null) offset += getTop(e.offsetParent);
        return offset;
    }

    function getLeft(e) {
        var offset = e.offsetLeft;
        if (e.offsetParent != null) offset += getLeft(e.offsetParent);
        return offset;
    }
    //console.log(getTop(startEle),getLeft(startEle))
    startEle.style.position="absolute"
    endEle.style.position="absolute"
    endEle.style.top=getTop(startEle)+startEle.clientHeight+2+"px"
    endEle.style.left=getLeft(startEle)+180+"px"


    startEle2.style.position="absolute"
    startEle2.style.left=startEle.style.left
    startEle2.style.top=endEle.style.top


    endEle2.style.position="absolute"
    endEle2.style.left=endEle.style.left
    endEle2.style.top=startEle.style.top

    const showEffectName = 'draw'; //从起点到终点绘制线条 fade 淡入淡出 none 无效果，即直接显示
    const animOptions = {// 动画参数
        duration: 1000, //持续时长
        timing: 'ease-in', // 动画函数
    };

    function sleep(time){
        var timeStamp = new Date().getTime();
        var endTime = timeStamp + time;
        while(true){
            if (new Date().getTime() > endTime){
                return;
            }
        }
    }
    function tuodong (event) {
        //endEle.setPointerCapture(1);//捕获点击事件到自己身上，避免全选时其他元素被波及
        (this.setCapture && this.setCapture())||(this.setPointerCapture && this.setPointerCapture(1))
        //点上后，计算鼠标跟div的相对位置差
        event=event||window.event;
        var mx=event.clientX;
        var my=event.clientY;
        var dx=this.offsetLeft;
        var dy=this.offsetTop;
        var cx=mx-dx;
        var cy=my-dy;
        //定一个全局鼠标移动事件
        let obj=this //this表示被拖动的div
        document.onmousemove=function(event){
            event=event||window.event;
            //获取鼠标位置
            var mx=event.clientX;
            var my=event.clientY;
            //算出div顶点应该出现的位置
            var dx=mx-cx;
            var dy=my-cy;
            //重新定义div的位置
            obj.style.left=dx+"px";
            obj.style.top=dy+"px";
            for(var i in obj.leader_lines){
                obj.leader_lines[i].position()
            }
            //定一个全局鼠标抬起事件，防止点上上层下层不触发。
            document.onmouseup=function () {
                //console.log(obj.style.left,obj.style.top); //用这里触发ajax存储到数据库中
                //全局鼠标移动事件为空
                document.onmousemove=null;
                //全局鼠标抬起事件为空
                document.onmouseup=null;
                //endEle.releasePointerCapture(1);//释放捕获鼠标事件，否则会连续捕获下去，以后次次点击都承接到他自己身上了。
                (obj.releaseCapture && obj.releaseCapture() ) ||(obj.releasePointerCapture && obj.releasePointerCapture(1) )
            }
        }
        return false//取消拖拽的搜索默认行为
    }
    function f(tou,wei,kaishiyanse,jieshuyanse,yangshi) {//头,尾,开始颜色,结束颜色,样式
        let new_line;
        let options={
            startPlugColor: kaishiyanse, // 渐变色开始色#ff3792
            endPlugColor: jieshuyanse, // 渐变色结束色
            gradient: true, // 使用渐变色
            hide: true,//这个东西还跟线条画出有关系,true 则线条画出,false则线条不画出
        }
        if(yangshi=="xuxian"){//如果是虚线就设置这一项
            options.dash={animation: true}
        }
        new_line=new LeaderLine(
            tou,wei,options
        )
        function addLineInElement(element,line) {
            if(element.leader_lines){
                element.leader_lines.push(line)
            }else{
                element.leader_lines=[];
                element.leader_lines.push(line)
            }
            element.onmousedown=tuodong
        }
        addLineInElement(tou,new_line)
        addLineInElement(wei,new_line)

        new_line.show(showEffectName, animOptions)
        return new_line;//返回一个函数
    }

    let leader_line=f(startEle,endEle,kaishiyanse='#ff3792',jieshuyanse='#fff386',yanshi="xuxian");

    const leader_line2 = f(startEle2, endEle2, kaishiyanse = '#ff3792', jieshuyanse = '#fff386', yanshi = "shixian");

    let leader_line3=f(startEle,endEle2,kaishiyanse='#ff3792',jieshuyanse='#fff386',yanshi="xuxian");
    objs=document.getElementsByClassName("target")
    for(var i in objs){
        //为每个div添加了add模块
        objs[i].onmouseover = function (){
            let add=document.createElement("div")
            add.style.position="absolute" //relative absolute
            add.style.left=this.offsetLeft+this.offsetWidth+"px"
            add.style.top=this.offsetTop+this.offsetHeight-30+"px"
            add.style.width=50+"px"
            add.style.height=30+"px"
            add.style.background="green"
            add.id=this.id+"AddId"
            add.innerHTML="create"

            document.body.append(add)

            // console.log("add图标的横坐标:"+add.style.left,"add图标的纵坐标:"+add.style.top)
            // console.log("大div的左上角坐标为:"+this.offsetLeft,this.offsetTop)
            // console.log("大div的宽度和高度是:"+this.offsetWidth,this.offsetHeight)
            // console.log("大div的右下角坐标为:"+(this.offsetLeft+this.offsetWidth),(this.offsetTop+this.offsetHeight))
            // console.log("小div的左上角坐标为:"+(this.offsetLeft+this.offsetWidth-10),(this.offsetTop+this.offsetHeight-10))
        }
        //当鼠标移出div模块时,add模块也随之消失;这里面有矛盾!
        //当鼠标移出div时,进入add模块后,add模块不应该消失
        //当鼠标移出div,并没有进入add模块时,add模块应该消失
            //关键点在于判断,移出div时,是否进入add模块
        objs[i].onmouseout=function(event){
            var addEle = document.getElementById(this.id+"AddId");
            var x=event.clientX;
            var y=event.clientY;
            var divx1 = addEle.offsetLeft;  //距离边界的距离
            var divy1 = addEle.offsetTop; //距离边界的距离
            var divx2 = addEle.offsetLeft + addEle.offsetWidth; //右下点距离边界的距离
            var divy2 = addEle.offsetTop + addEle.offsetHeight; //右下点距离边界的距离
            if( x < divx1 || x > divx2 || y < divy1 || y > divy2){
                //鼠标小于左上点横方向
                //鼠标大于右下点横方向
                //鼠标小于左上点竖方向
                //鼠标大于右下点竖方向
                //此时鼠标不在这个模块中
                //那就可以删除了
                document.body.removeChild(addEle)
            }else{
                //否则,鼠标在这个模块中
                //那就不删除
                addEle.onclick=function (event) {
                    let newDiv=document.createElement("div")
                    //获取当前对象的位置
                    var addDivX = this.offsetLeft
                    var addDivY = this.offsetTop
                    newDiv.style.position="absolute"
                    newDiv.style.left=this.offsetLeft+this.offsetWidth+"px"
                    newDiv.style.top=this.offsetTop+this.offsetHeight+30+"px"
                    newDiv.style.width=50+"px"
                    newDiv.style.height=30+"px"
                    newDiv.style.background="#00FF00"
                    newDiv.id=this.id.replace("AddId", "")+"NewDiv"
                    document.body.append(newDiv)
                }
                addEle.onmouseout=function (event) {
                    this.id.replace("AddId", "")
                    var divObj = document.getElementById(this.id.replace("AddId", ""));
                    var x=event.clientX;
                    var y=event.clientY;
                    var divx1 = divObj.offsetLeft;  //距离边界的距离
                    var divy1 = divObj.offsetTop; //距离边界的距离
                    var divx2 = divObj.offsetLeft + divObj.offsetWidth; //右下点距离边界的距离
                    var divy2 = divObj.offsetTop +  divObj.offsetHeight; //右下点距离边界的距离
                    if( x < divx1 || x > divx2 || y < divy1 || y > divy2){
                        //移出了divObj,删除add模块
                        document.body.removeChild(this)
                    }else{
                        //没移出divObj,不删除
                    }
                }
            }
        }
    }
</script>
</body>
</html>